﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Cubicle.Core.Interfaces;
using Cubicle.Core.Processors.Parameter;
using Cubicle.Core.Shared;

namespace Cubicle.Core.Processors.Construct
{
    [Export("Cubicle.Processors.Construct.DictionaryConstructProcessor", typeof(IProcessor<InstructionRequest>))]
    [ExportMetadata("Name", "DictionaryConstructProcessor")]
    [ExportMetadata("Description", "Creates an instance of type System.Collections.Generic.Dictionary`2")]
    public class DictionaryConstructProcessor : InstructionRequestProcessor
    {
        [Import]
        private ParameterProcessor _parameterProcessor = null;
        private static Type _dictType = typeof (Dictionary<,>);

        [ImportingConstructor]
        public DictionaryConstructProcessor() : base(RequestType.CustomConstruct) { }

        #region Overrides of Processor<InstructionRequest>

        public override bool Condition(InstructionRequest request)
        {
            return base.Condition(request)
                && request.TargetType != null
                && request.TargetType.IsGenericType
                && request.TargetType.GetGenericTypeDefinition() == _dictType;
        }

        public override InstructionRequest ConditionalProcess(InstructionRequest request)
        {
            var type = request.TargetType;
            var parameters = request.Inst.Parameters;
            if (request.TargetType.IsGenericTypeDefinition)
            {
                var arg1 = TypeCache.GetType(request.Inst.ClassArgs[0]);
                var arg2 = TypeCache.GetType(request.Inst.ClassArgs[1]);
                type = type.MakeGenericType(new[] { arg1, arg2 });
            }
            var result = type.GetConstructor(new Type[0]).Invoke(null) as IDictionary;
            var targetKeyType = type.GetGenericArguments()[0];
            var targetValueType = type.GetGenericArguments()[1];
            foreach (object[] t in parameters)
            {
                var keyRequest = new ParameterRequest(targetKeyType, t[0]);
                var valueRequest = new ParameterRequest(targetValueType, t[1]);
                _parameterProcessor.Process(keyRequest);
                _parameterProcessor.Process(valueRequest);
                result.Add(keyRequest.Result, valueRequest.Result);
            }
            request.Complete(result);
            return request;
        }

        #endregion
    }
}